import { System, World } from '@ecs/index'
import { Image, Position, Render, Rotate, Size, Text } from '../components'

/**
 * 渲染系统
 * @description 通过canvas渲染
 */
export class RenderSystem extends System {
  constructor(private readonly context: CanvasRenderingContext2D) {
    super()
  }

  public update(world: World): void {
    // [路径管理]1.清除上一次绘制区域
    this.context.clearRect(
      0,
      0,
      this.context.canvas.width,
      this.context.canvas.height
    )

    // 根据渲染层级生成渲染队列
    const renderQueue = world.view(Render).sort((a, b) => {
      const [, componentMapA] = a
      const [, componentMapB] = b
      const renderA = componentMapA.get(Render)
      const renderB = componentMapB.get(Render)
      return renderA.zindex - renderB.zindex
    })

    // 渲染队列执行渲染
    for (const [, componentMap] of renderQueue) {
      const render = componentMap.get(Render)
      const position = componentMap.get(Position)
      const rotate = componentMap.get(Rotate)
      const image = componentMap.get(Image)
      const size = componentMap.get(Size)
      const text = componentMap.get(Text)

      // [路径管理]2.保存当前上下文状态
      this.context.save()

      // [路径变换]3.设置变换（位移、旋转、缩放）
      const mx = position?.x + size?.w / 2
      const my = position?.y + size?.h / 2
      this.context.translate(mx, my) // canvas旋转是基于绘图区域原点的，因此需要调整到精灵原点
      this.context.rotate(rotate?.angle)
      this.context.translate(-mx, -my) // 旋转后再次平移回来

      if (render.type === 'image') {
        image.clipCount += image.clipSpeed
        image.clipCount >= image.clips.length - 1 && (image.clipCount = 0)
        const clip = image.clips[Math.floor(image.clipCount)]
        // [路径绘制]5.执行图片绘制
        this.context.drawImage(
          image?.source,
          clip?.sx,
          clip?.sy,
          clip?.sw,
          clip?.sh,
          position?.x,
          position?.y,
          size?.w,
          size?.h
        )
      } else if (render.type === 'text') {
        // [路径样式]4.设置样式（尺寸、颜色、阴影、字体）
        this.context.font = text.font
        this.context.fillStyle = text.fillStyle
        // [路径绘制]5.执行文本绘制
        this.context.fillText(text.text, position.x, position.y, text.maxWidth)
      }

      // [路径管理]6.恢复上一次上下文状态
      this.context.restore()
    }
  }

  public destory(): void {}
}
